import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.SimpleTimeZone;
import java.util.StringTokenizer;

import javax.swing.text.AbstractDocument.Content;


public class Client extends Thread{
	private Socket connection;
	private String input;
	private static InetAddress client;
	private char httpType;
	private String path;
	private Boolean gotpath;
	int timeouttime =-1;
	

	
	public Client(Socket socket, InetAddress clientAdd){
		//since we are going to do multi-threading, we need to 
		//start a thread every time a client sends a request
		connection = socket;
		client = clientAdd;
		gotpath = false;
		run();
	}
	
	public Client(Socket socket, InetAddress clientAdd, String pathName){
		//since we are going to do multi-threading, we need to 
		//start a thread every time a client sends a request
		connection = socket;
		client = clientAdd;
		path = pathName;
		gotpath = true;
		run();
	}
		
	
	
	public void run(){

		try{
			//we want to start reading in the request
			BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
			//we will use this to send back what the client requested: header + file
			DataOutputStream out = new DataOutputStream(connection.getOutputStream());
				
			while(timeouttime!=0){
				timeouttime = handle_http(in, out);
			}
			System.out.print("close");
			
			in.close();
			out.close();
			connection.close();
		}
		catch (Exception ex){
			System.err.println(ex.toString());
		}	
			
		
		
	}


	private int handle_http(BufferedReader in, DataOutputStream out) throws IOException {
		int request = 0, timeouttime =0, keepalivetime=0;//1=get, 2=head, 3=put, 4=delete, 5=trace
		int fileType = 0; //1 = .exe 2 = jpg  3  
		//these will be used to substring and get the path of file 
		//int start = 0;
		//int end = 0;
		//int start1 = 0;
		//int end2 = 0;
		FileInputStream fileRequested = null;
		
		StringTokenizer tokenizer = new StringTokenizer(in.readLine());
		String method = tokenizer.nextToken();
		//String filename = tokenizer.nextToken().substring(1);
		String filename = tokenizer.nextToken();

		//if (!gotpath){
		//	path = new File(filename).getAbsolutePath();
		//}
		String type = tokenizer.nextToken();
		char version = type.charAt(type.length()-1);
		if(method.equals("PUT")){
			String contentlength = tokenizer.nextToken();
			System.out.println("the content length is: " + contentlength);
		}
		
		System.out.println("method is: " + method);
		System.out.println("filename is: " + filename);
		System.out.println("type is: " + type);
		System.out.println("version is: " + version);
		

		try{
		
			if(method.equals("GET")){
				request = 1;
			}
			if(method.equals("HEAD")){
				request = 2;

			}
			if(method.equals("PUT")){
				request = 3;

			}
			if(method.equals("DELETE")){
				request = 4;

			}
			if(method.equals("TRACE")){
				request = 5;
			}	
			//this means that the commands we support was not inputted
			//so we cannot handle this!!
			if(request == 0){
				try{
					out.writeBytes(headerStatusCode(501,version));
					out.close();

					//return;
				}
				catch (Exception ex) {
					System.err.println("ERROR1: " + ex.getMessage());
				}
			}
			
			
			System.out.println("The client is requesting: " + filename + "\n");
		}
		catch (Exception ex){
			System.err.println("ERROR2: " + ex.getMessage());
		}
		
		
		//lets try to open the file, if not then 404
		try{
			if(gotpath){
				filename = path + filename;
			}
			else{
				filename = "." + filename;
			}
			fileRequested = new FileInputStream(filename);
		}
		
		catch(Exception ex){
			try{
				//now send the 404 error. we pass 0 since its not a valid file
				out.writeBytes(headerStatusCode(404,version));
				out.writeBytes("\r\n");
				//since the file is not valid then we can automatically
				//close the stream regardless.
				out.close();
			}
			catch(Exception e){
			}
			System.err.println("ERROR3: " + ex.getMessage());			
		}
		

		//so if the file is found, we need to know what type it is to
		//send back to client.  We do NOT check for html because we will
		//assume that is the default
		try{
			if(filename.endsWith(".zip")){
				fileType = 1;
			}
			if(filename.endsWith(".jpg") || filename.endsWith(".jpeg")){
				fileType = 2;
			}
			if(filename.endsWith(".bmp")){
				fileType = 3;
			}
			if(filename.endsWith(".gif")){
				fileType = 4;
			}
			if(filename.endsWith(".png")){
				fileType = 5;
			}
			if(filename.endsWith(".exe")){
				fileType = 6;
			}			
			else{
				fileType = 10;
			}
			
			SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ");
			Date modifiedDate = null;
			File temp = new File(filename);
			Date mod = new Date(temp.lastModified());
			modifiedDate = dateFormat.parse(dateFormat.format(mod));
			
			out.writeBytes(headerStatusCode(200,version));
			out.writeBytes("\r\n");
			out.writeBytes(headerDate());
			out.writeBytes("\r\n");
			out.writeBytes(headerFileType(fileType));
			out.writeBytes("\r");
			out.writeBytes("Content-Length:"+fileRequested.available());
			out.writeBytes("\r\n");
			out.writeBytes("Last-Modified:"+ modifiedDate.toString());
			out.writeBytes("\r\n\r\n");			

			//do the actual method requests
			
			//GET
			if(request == 1){		
					int b;
					
					Date conditionalDate = null;
					String content = in.readLine();

					while(!(content.equals(""))){
						if(content.startsWith("If-Modified-Since")){
							conditionalDate = dateFormat.parse(content.substring(17).trim());
							break;
						}
						if(content.startsWith("Keep-Alive:")){
							keepalivetime = Integer.parseInt(content.substring(11).trim());
						}
						if(content.equals("")){
							break;
						}
						content = in.readLine();
					
					}
					
					if(conditionalDate != null && modifiedDate.compareTo(conditionalDate)==0){
						headerStatusCode(304, version);
					}
					else{
						while((b = fileRequested.read()) != -1){
							out.writeByte(b);
						}
				    }
			}
			
			//HEAD
			else if(request == 2){
				String content = in.readLine();
				while(!(content.equals(""))){
					if(content.startsWith("Keep-Alive:")){
						keepalivetime = Integer.parseInt(content.substring(11).trim());
					}
					content = in.readLine();
				}	
			}
			//PUT
			else if(request == 3){
				String content = in.readLine();
				int length = -1;
				while(!(content.equals(""))){
					if(content.startsWith("Content-Length:")){
						length = Integer.parseInt(content.substring(15).trim());
					}
					if(content.startsWith("Keep-Alive:")){
						keepalivetime = Integer.parseInt(content.substring(11).trim());
					}
					content = in.readLine();
				}
				char [] body = new char[length];
				in.read(body);
				String bodyBytes = new String(body);
				FileOutputStream writtenFile = new FileOutputStream(filename);
				writtenFile.write(bodyBytes.getBytes());				
			}
			
			//DELETE
			else if(request == 4){
				Boolean delete = new File(filename).delete();
				String content = in.readLine();
				while(!(content.equals(""))){
					if(content.startsWith("Keep-Alive:")){
						keepalivetime = Integer.parseInt(content.substring(11).trim());
					}
					content = in.readLine();
				}	
			}
			
			
			//TRACE
			else if(request == 5){
				String firstLine = method + " " + filename + " " + type;
				out.writeBytes(firstLine);
				String content = in.readLine();
				System.out.print("WHATEVER"+content);
				while(!(content.equals(""))){
					out.writeBytes(content);
					if(content.startsWith("Keep-Alive:")){
						keepalivetime = Integer.parseInt(content.substring(11).trim());
					}
					content = in.readLine();
				}
			}
	        
			
			//if it is 1.0 then automatically close connection
			if(type.equals("HTTP/1.0")){
				
				timeouttime =0;
				out.writeBytes("\r\n");				
				//out.close();
				fileRequested.close();
				//connection.close();
			}
			
			if(type.equals("HTTP/1.1")){
				//and keepalive time
				timeouttime = keepalivetime;
				//figure out that you dont close unless the timer of 5 seconds has occurred
				in.readLine();
				out.writeBytes("\r\n");	
				//out.close();
				fileRequested.close();
				//connection.close();

					
			}
		}
					
		
		catch(Exception ex){
		}
		 
		System.out.print(timeouttime);
		return timeouttime;
	}


	private String headerStatusCode(int errorCode, char hType) {
		String status = "HTTP/1." + hType +" ";
		
		//were going to have errors 400,403.404,411,501
		switch(errorCode){
		case 200:
			status = status + "200 OK";
			break;
		case 400:
			status = status + "400 Bad Request";
			break; 
		case 403:
			status = status + "403 Forbidden";
			break; 
		case 404:
			status = status + "404 Not Found";
			break; 
		case 411:
			status = status + "411 Length Required";
			break; 
		case 304:
			status = status + "304 Not Modified";
			break; 
		case 501:
			status = status + "501 Not Implemented";
			break; 
		}
		return status;
	}

	private String headerDate() {
		
		//time in GMT format
		SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ");
		dateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
		String date = dateFormat.format(new Date());
		//String dateAsString = dateFormat.format(date);
		
		//need to add time
		//date = date+"\r\n"; //end of the header	
		return date;
	}
	
	private String headerFileType(int filetype) {
		String fileString = "";
		//for content type
		switch(filetype){
		case 0: 
			break;
		case 1:
			fileString = fileString + "Content-Type: application/zip\r\n";
			break;
		case 2:
			fileString = fileString + "Content-Type: image/jpeg\r\n";
			break;
		case 3:
			fileString = fileString + "Content-Type: image/bmp\r\n";
			break;
		case 4:
			fileString = fileString + "Content-Type: image/gif\r\n";
			break;
		case 5:
			fileString = fileString + "Content-Type: image/png\r\n";
			break;
		case 6:
			fileString = fileString + "Content-Type: image/exe\r\n";
			break;
		default:
			fileString = fileString + "Content-Type: text/html\r\n";
			break;	
		}

		//need to add content length
		
		//fileString = fileString + "\r\n"; //end of the header
		return fileString;
	}

	
	
	
}


